﻿using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using ClosedXML.Excel;
using Haimen.Excel;

namespace HmLab.Func1;

internal class LbMergeSystemExport {

  /// <summary>
  /// <see cref="Haimen.Func1.HuallExportMerger"/>
  /// </summary>
  public void Run() {
    Console.WriteLine("-------LbMergeSystemExportLbMergeSystemExport");
    var Dir = (string dirStr) => {
      Debug.Assert(Directory.Exists(dirStr));
      return dirStr;
    };

    string inDir = Dir(@"E:\work_etc\nina\2023haimen2\workshop_cslab\输O入" + TODAY);
    string outDir = Dir(@"E:\work_etc\nina\2023haimen2\workshop_cslab\输Q出");

    string loadTpl = @"E:\work_etc\nina\2023haimen2\workshop_cs\haimen\resources\func1\load.xlsx";
    string lookupPath = @"E:\work_etc\nina\2023haimen2\workshop_cs\haimen\resources\func1\vlookup.xlsx";

    // 获取数据源sheet名
    (DataGroupCfg[] groupAll, string outPath) = PrepareOutput(outDir, loadTpl);

    // 按sheet名把文件路径分组
    string[] fileList = Directory.GetFiles(inDir);
    Debug.Assert(fileList.Length > 0);

    (string path, string name)[] inFiles = fileList.Order()
      .Select(p => (p, Path.GetFileNameWithoutExtension(p) ?? ""))
      .ToArray();

    var GetGroup = (string group) => inFiles
      .Where(f => f.name.StartsWith(group))
      .Select(f => f.path)
      .ToArray();

    (string name, string[] path)[] groupPath = groupAll
      .Select(g => g.Name)
      .Select(g => (g, GetGroup(g)))
      .ToArray();

    // 并发读取文件数据
    AppConfigRoot config = _appCfgReader.Read(groupAll, lookupPath);
    var ReadGroup = (string[] paths, string group) => paths
      .Select(p => Task.Run(() => _dataLoader.Load(p, group, config)))
      .ToArray();

    (string group, Task<HuallLoadResult>[])[] groupLoading = groupPath
      .Where(g => g.path.Length > 0)
      .Select(g => (g.name, ReadGroup(g.path, g.name)))
      .ToArray();

    // 按组写入对应sheet
    WriteToOutput(outPath, groupLoading).Wait();
  }

  (DataGroupCfg[], string) PrepareOutput(string outDir, string templatePath) {
    string outPath = Path.Join(outDir, $"数据源_24{TODAY}.xlsx");
    File.Copy(templatePath, outPath, overwrite: true);

    DataGroupCfg[] groupList = _groupCfgReader.Read(outPath);
    return (groupList, outPath);
  }

  async Task WriteToOutput(string outPath, (string group, Task<HuallLoadResult>[])[] groupLoad) {
    using FileStream stream = _excelUtil.OpenWrite(outPath);
    using XLWorkbook outBook = new(stream);

    foreach ((string group, Task<HuallLoadResult>[] loadList) in groupLoad) {
      Debug.Assert(loadList.Length > 0);
      IXLWorksheet sheet = outBook.Worksheet(group);

      int rowCursor = 2; // 多个表要往下续写
      foreach (Task<HuallLoadResult> loading in loadList) {
        HuallLoadResult result = await loading;
        Console.WriteLine(result.Name);

        foreach (HuallMergeRow row in result.Rows) {
          object[] colVal = row.ColVal;
          for (int c = 0; c < colVal.Length; c++) {
            XLCellValue cellVal = ToCellVal(colVal[c]);
            sheet.Cell(rowCursor, c + 1).SetValue(cellVal);
          }
          rowCursor++;
        }
      }
    }

    string lastWrite = groupLoad[^1].group;
    foreach (IXLWorksheet sheet in outBook.Worksheets) {
      bool active = lastWrite.Equals(sheet.Name);
      sheet.SetTabSelected(active);
      sheet.SetTabActive(active);
    }

    outBook.Save();
  }

  XLCellValue ToCellVal(object val) {
    if (val is int valInt) {
      return (XLCellValue)valInt;
    }
    if (val is double valDoub) {
      return (XLCellValue)valDoub;
    }

    string valStr = (string)val;
    if (DateTime.TryParseExact(valStr, "yyyy-MM-dd",
        CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime varDate)) {
      return (XLCellValue)varDate;
    }

    return (XLCellValue)valStr;
  }

  const string TODAY = "test";

  readonly LbReadResultConfig.GroupAll _groupCfgReader = new(new());
  readonly LbReadResultConfig.AppConfig _appCfgReader = new(new());

  readonly ExportDataMerger _dataLoader = new();
  readonly ExcelFileUtils _excelUtil = new();
}
